package com.game.net.server.websocket;

import com.game.net.BaseServer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.handler.stream.ChunkedWriteHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class WebSocketNettyServer extends BaseServer {
	private Logger logger = LoggerFactory.getLogger(WebSocketNettyServer.class);
	static boolean SSL = System.getProperty("ssl") != null;
	private int port = Integer.parseInt(System.getProperty("port", SSL ? "8443" : "8080"));

	public void init(int port,final SimpleChannelInboundHandler handler) {
		this.port = port;
		logger.info("start server");
		// Configure SSL.
		SslContext sslCtx = null;

		if (SSL) {
			SelfSignedCertificate ssc = null;
			try {
				ssc = new SelfSignedCertificate();
				sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			sslCtx = null;
		}

		EventLoopGroup bossGroup = new NioEventLoopGroup(1);
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		try {
			ServerBootstrap b = new ServerBootstrap();
			b.group(bossGroup, workerGroup)
					.channel(NioServerSocketChannel.class)
					.handler(new LoggingHandler(LogLevel.INFO))
					.childHandler(new ChannelInitializer<SocketChannel>() {
						@Override
						public void initChannel(SocketChannel ch) throws Exception {
							ChannelPipeline pipeline = ch.pipeline();
							pipeline.addLast(new HttpServerCodec());
							pipeline.addLast(new HttpObjectAggregator(65536));
							pipeline.addLast(new ChunkedWriteHandler());
							pipeline.addLast(new WebSocketServerProtocolHandler("/ws", null, true));
							pipeline.addLast(handler);
						}
					});

			Channel ch = b.bind(8080).sync().channel();

			System.out.println("Open your web browser and navigate to " +
					(SSL ? "https" : "http") + "://127.0.0.1:" + this.port + '/');

			ch.closeFuture().sync();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}
	}

	public static void main(String[] args) throws Exception {
		WebSocketNettyServer nettyWebSocketServer = new WebSocketNettyServer();
		nettyWebSocketServer.init(8080,null);
	}
}
